package org.sczfdf.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import org.sczfdf.bean.CmdInfo;
import org.sczfdf.conf.GitConf;
import org.sczfdf.exception.SyncException;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Created by cgb
 * @date 2023/1/31
 */
public class CmdUtil {
    private static final String LOG_FORMAT = "执行命令[%s]%s cmd:[%s] dir:[%s] %s";
    private static final String LOG_CHECK_INTERVAL_FORMAT = "%s命令[%s]执行间隔[%s秒]. 上次执行时间%s";

    private static final Integer SUCCESS = 0;

    private static final Map<String, File> DIR_CACHE = new HashMap<>();
    private static final Map<CmdInfo, LocalDateTime> EXECUTE_RECORD_CACHE = new HashMap<>();

    public static String cmd(CmdInfo cmdInfo) {
        String resultStr = "";
        if (!checkInterval(cmdInfo)) {
            return resultStr;
        }

        String describe = cmdInfo.getDescribe();
        String dir = StrUtil.isNotBlank(cmdInfo.getDir()) ? cmdInfo.getDir() : GitConf.get().getGitPath();
        List<String> cmds = cmdInfo.getCmds();

        DIR_CACHE.putIfAbsent(dir, new File(dir));
        if (cmds == null || cmds.isEmpty()) {
            LogUtil.logError("cmd 命令错误" + cmdInfo);
            return resultStr;
        }

        ProcessBuilder pb = new ProcessBuilder(cmds);
        pb.redirectErrorStream(true);
        pb.directory(DIR_CACHE.get(dir));

        String cmdStr = String.join(" ", cmds);
        LogUtil.logInfo(String.format(LOG_FORMAT, describe, "　　", cmdStr, dir, ""));
        try {
            Process process = pb.start();

            resultStr = RuntimeUtil.getResult(process, StandardCharsets.UTF_8);
            if (process.waitFor() != SUCCESS) {

                LogUtil.logError(String.format(LOG_FORMAT, describe, "失败", cmdStr, dir, "result:\n" + resultStr));
                throw new SyncException(cmdStr + " error " + resultStr);

            } else {
                LogUtil.logInfo(String.format(LOG_FORMAT, describe, "成功", cmdStr, dir, "result:\n" + resultStr));

            }
        } catch (IOException | InterruptedException e) {
            throw new SyncException(cmdStr + "\n" + e.getMessage() + "\n" + resultStr);
        }
        return resultStr;
    }

    private static boolean checkInterval(CmdInfo cmdInfo) {
        int watchInterval = cmdInfo.getWatchInterval();
        if (watchInterval == 0) {
            return true;
        }

        boolean pass;
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastExecuteTime;
        if (EXECUTE_RECORD_CACHE.containsKey(cmdInfo)) {
            lastExecuteTime = EXECUTE_RECORD_CACHE.get(cmdInfo);

            Duration between = LocalDateTimeUtil.between(lastExecuteTime, now);
            if (between.getSeconds() > watchInterval) {
                EXECUTE_RECORD_CACHE.put(cmdInfo, now);
                pass = true;
            } else {
                pass = false;
            }
        } else {
            lastExecuteTime = LocalDateTimeUtil.of(0);
            EXECUTE_RECORD_CACHE.put(cmdInfo, now);
            pass = true;
        }

        LogUtil.logInfo(String.format(
                        LOG_CHECK_INTERVAL_FORMAT,
                        pass ? "准备执行" : "间隔不足拒绝执行, ",
                        String.join(" ", cmdInfo.getCmds()),
                        watchInterval,
                        DateUtil.formatLocalDateTime(lastExecuteTime)
                )
        );
        return pass;
    }
}
